package com.supor.nfc.lib.common;

import android.os.Build;
import android.util.Log;

import com.supor.nfc.lib.utils.ByteUtil;
import com.supor.nfc.lib.utils.HexUtil;

import java.io.ByteArrayOutputStream;
import java.io.DataOutputStream;
import java.io.IOException;
import java.nio.charset.StandardCharsets;
import java.util.Arrays;
import java.util.List;

/**
 * ---------------------------------------------------------------- <br>
 * Copyright (C) 2014-2020, by het, Shenzhen, All rights reserved.  <br>
 * ---------------------------------------------------------------- <br>
 * <p>
 * 描述: BuildHelper <br>
 * 作者: lei <br>
 * 日期: 2020/9/7 <br>
 */
public class BuildHelper {

    /**
     * 压力锅：通过压力锅协议组装一个完整的NFC数据包
     *
     * @param id    帧类型
     * @param name  数据内容
     * @param datas 数据内容
     * @return 从起始标志到检验码的byte[]数据包
     */
    public static byte[] buildData(int id, String name, List<ParamInfo> datas) {
        // if (datas == null || datas.size() <= 0) {
        //     Logc.e("data list is null");
        //     return null;
        // }
        try {
            ByteArrayOutputStream outputStream = new ByteArrayOutputStream();
            DataOutputStream dataOutputStream = new DataOutputStream(outputStream);
            // ID (数字食谱序列号)
            dataOutputStream.writeShort(id);
            // NAME (数字食谱名称)
            byte[] nameBytes = new byte[20];
            if (name != null) {
                byte[] nBytes = name.getBytes(StandardCharsets.UTF_8);
                System.arraycopy(nBytes, 0, nameBytes, 0, nBytes.length);
            }
            dataOutputStream.write(nameBytes);
            int size = 0;
            if (datas == null || datas.size() <= 0) {
                Log.e("build", "data list is null");
            } else {
                size = datas.size();
            }
            // 数字食谱总步骤
            dataOutputStream.writeByte(size);

            if (size > 0) {
                for (int i = 0; i < size; i++) {
                    ParamInfo info = datas.get(i);
                    // 步骤
                    dataOutputStream.writeByte((i + 1));
                    // 食谱总字节数
                    dataOutputStream.writeByte(12);
                    // 方法
                    dataOutputStream.write("M".getBytes(StandardCharsets.UTF_8));
                    dataOutputStream.writeByte((info.funName + 1));
                    // 火力
                    dataOutputStream.writeShort(info.fire);
                    // 压力KP
                    dataOutputStream.writeByte(info.press);
                    // 功率
                    dataOutputStream.writeByte(info.power);
                    // 搅拌
                    dataOutputStream.writeByte(info.stir);
                    // 排气
                    dataOutputStream.writeByte(info.venting);
                    // 时间
                    byte[] times = HexUtil.reverse(HexUtil.intToBytes(info.time));
                    dataOutputStream.write(times, 1, 3);
                    // 结束条件
                    dataOutputStream.writeByte((info.condition + 1));
                }
            }

            return outputStream.toByteArray();
        } catch (IOException e) {
            e.printStackTrace();
            return null;
        }
    }

    /**
     * 破壁机：通过破壁机协议组装一个完整的NFC数据包
     *
     * @param id    帧类型
     * @param name  数据内容
     * @param datas 数据内容
     * @return 从起始标志到检验码的byte[]数据包
     */
    public static byte[] buildDataForBlender(int id, String name, List<ParamInfo> datas) {
        try {
            ByteArrayOutputStream outputStream = new ByteArrayOutputStream();
            DataOutputStream dataOutputStream = new DataOutputStream(outputStream);
            // ID (数字食谱序列号)
            dataOutputStream.writeShort(id);
            // NAME (数字食谱名称)
            byte[] nameBytes = new byte[20];
            if (name != null) {
                byte[] nBytes = name.getBytes(StandardCharsets.UTF_8);
                System.arraycopy(nBytes, 0, nameBytes, 0, nBytes.length);
            }
            dataOutputStream.write(nameBytes);
            int size = 0;
            if (datas == null || datas.size() <= 0) {
                Log.e("build", "data list is null");
            } else {
                size = datas.size();
            }
            // 数字食谱总步骤
            dataOutputStream.writeByte(size);

            if (size > 0) {
                for (int i = 0; i < size; i++) {
                    ParamInfo info = datas.get(i);
                    // 步骤
                    dataOutputStream.writeByte((i + 1));
                    // 食谱总字节数
                    dataOutputStream.writeByte(11);
                    // 方法
                    dataOutputStream.write("M".getBytes(StandardCharsets.UTF_8));
                    dataOutputStream.writeByte((info.funName + 5));
                    // 火力
                    dataOutputStream.writeShort(info.fire);
                    // 压力KP
                    // dataOutputStream.writeByte(info.press);
                    // 功率
                    dataOutputStream.writeByte(info.power);
                    // 搅拌
                    dataOutputStream.writeByte(info.stir);
                    // 正反转
                    dataOutputStream.writeByte(info.reverse);
                    // 排气
                    // dataOutputStream.writeByte(info.venting);
                    // 时间
                    byte[] times = HexUtil.reverse(HexUtil.intToBytes(info.time));
                    dataOutputStream.write(times, 1, 3);
                    // 结束条件
                    dataOutputStream.writeByte((info.condition + 1));
                }
            }

            return outputStream.toByteArray();
        } catch (IOException e) {
            e.printStackTrace();
            return null;
        }
    }

    /**
     * 破壁机：通过破壁机协议组装一个完整的NFC数据包
     * @param head NFC状态标志位F0、F1、F2、F3
     * @param data 下行数据
     * @return 从起始标志到检验码的byte[]数据包
     */
    public static byte[] buildDataForBlender(byte[] head, byte[] data) {
        try {
            ByteArrayOutputStream outputStream = new ByteArrayOutputStream();
            DataOutputStream dataOutputStream = new DataOutputStream(outputStream);
            dataOutputStream.write(head);
            dataOutputStream.write(data);
            return outputStream.toByteArray();
        } catch (IOException e) {
            e.printStackTrace();
            return null;
        }
    }

    /**
     * 养生壶：通过养生壶协议组装一个完整的NFC私有数据包，总共20个字节
     *
     * @param data 数据内容
     * @return 从起始标志到检验码的byte[]数据包
     */
    public static byte[] buildDataForHealthPot(Param1 data) {
        try {
            ByteArrayOutputStream outputStream = new ByteArrayOutputStream();
            DataOutputStream dataOutputStream = new DataOutputStream(outputStream);
            // 功能
            dataOutputStream.writeByte(data.funName);
            // 阶段一火力/温度
            dataOutputStream.writeByte(data.fireStep1);
            // 阶段一制作时间
            dataOutputStream.writeShort(data.timeStep1);
            // 阶段二火力/温度
            dataOutputStream.writeByte(data.fireStep2);
            // 阶段二制作时间
            dataOutputStream.writeShort(data.timeStep2);
            // 阶段三火力/温度
            dataOutputStream.writeByte(data.fireStep3);
            // 阶段三制作时间
            dataOutputStream.writeShort(data.timeStep3);
            // 预约时间
            dataOutputStream.writeShort(data.appointmentTime);
            // 保温温度
            dataOutputStream.writeByte(data.keepTemp);
            // 保温时间
            dataOutputStream.writeShort(data.keepTime);
            // 高度(气压)
            dataOutputStream.writeByte(data.high);
            // 环境温度
            dataOutputStream.writeByte(data.temp);
            // 环境湿度
            dataOutputStream.writeByte(data.humi);
            // 显示亮度
            dataOutputStream.writeByte(data.light);
            // 声音
            dataOutputStream.writeByte(data.voice);

            return outputStream.toByteArray();
        } catch (IOException e) {
            e.printStackTrace();
            return null;
        }
    }

    /**
     * NFC智能：通过NFC智能设备协议组装一个完整的NFC私有数据包，总共20个字节
     *
     * @param data 数据内容
     * @return 从起始标志到检验码的byte[]数据包
     */
    public static byte[] buildDataForNFC(byte[] head, NfcRecipeParam data) {
        try {
            ByteArrayOutputStream outputStream = new ByteArrayOutputStream();
            DataOutputStream dataOutputStream = new DataOutputStream(outputStream);
            dataOutputStream.write(head);
            List<StepParam> stepParamList = data.stepParams;
            int stepTime = 0;
            int size = stepParamList.size();
            for (int i = 0; i < size; i++) {
                StepParam stepParam = stepParamList.get(i);
                // 类型: 01-火力/02-温度
                dataOutputStream.writeByte(stepParam.type);
                // 阶段值
                dataOutputStream.writeByte(stepParam.value);
                // 阶段制作时间
                dataOutputStream.writeShort(stepParam.time);
                // 阶段提示: 0-无提示，非0-有提示
                dataOutputStream.writeByte(stepParam.alarm);
                stepTime += stepParam.time;
            }
            // 剩余阶段填0
            if (size < 5) {
                dataOutputStream.write(new byte[(5 - size) * 5]);
            }

            if (data.appointmentTime != 0 && data.appointmentTime > System.currentTimeMillis()) {
                int remain = (int) ((data.appointmentTime - System.currentTimeMillis()) / (1000 * 60));
                int realTime = remain - stepTime;
                // 预约时间
                dataOutputStream.writeShort(Math.max(realTime, 0));
            } else {
                // 预约时间
                dataOutputStream.writeShort(0);
            }

            // 保温温度
            dataOutputStream.writeByte(data.keepTime == 0 ? 0 : data.keepTemp);
            // 保温时间
            dataOutputStream.writeShort(data.keepTime);
            // 高度(气压)
            dataOutputStream.writeByte(data.high);
            // 环境温度
            dataOutputStream.writeByte(data.temp);
            // 环境湿度
            dataOutputStream.writeByte(data.humi);
            // 显示亮度&声音
            dataOutputStream.writeByte(data.light);

            // 校验和
            byte[] checkBytes = Arrays.copyOfRange(outputStream.toByteArray(), 4,
                    outputStream.toByteArray().length);
            int checksum = ByteUtil.computeBodyNum(checkBytes);
            dataOutputStream.writeByte(checksum);

            return outputStream.toByteArray();
        } catch (IOException e) {
            e.printStackTrace();
            return null;
        }
    }

    /**
     * 根据参数协议构建参数包
     *
     * @return byte[]参数包
     */
    public static byte[] buildNFCParamData() {
        try {
            ByteArrayOutputStream outputStream = new ByteArrayOutputStream();
            DataOutputStream dataOutputStream = new DataOutputStream(outputStream);
            // id
            dataOutputStream.writeBytes("id=321");
            byte[] param = new byte[37];
            Arrays.fill(param, "&".getBytes()[0]);
            // Arrays.fill(param, "|".getBytes()[0]);
            System.arraycopy("0".getBytes(), 0, param, 0, 1);
            dataOutputStream.write(param);
            // cid
            dataOutputStream.writeBytes("&cid=");
            param = new byte[5];
            Arrays.fill(param, "&".getBytes()[0]);
            System.arraycopy("0".getBytes(), 0, param, 0, 1);
            // Arrays.fill(param, "|".getBytes()[0]);
            dataOutputStream.write(param);
            // step
            dataOutputStream.writeBytes("&step=");
            param = new byte[2];
            Arrays.fill(param, "&".getBytes()[0]);
            // Arrays.fill(param, "|".getBytes()[0]);
            dataOutputStream.write(param);
            // p
            dataOutputStream.writeBytes("&p=");
            dataOutputStream.write(getPlatform().getBytes(StandardCharsets.UTF_8));
            // String pin = "A-smartisan-oden00";
            // byte[] pis = pin.getBytes("UTF-8");
            // byte[] pins = new byte[20];
            // Arrays.fill(pins, "&".getBytes()[0]);
            // Arrays.fill(pins, "|".getBytes()[0]);
            // System.arraycopy(pis, 0, pins, 0, pin.length());
            // dataOutputStream.write(pins);

            return outputStream.toByteArray();
        } catch (IOException e) {
            e.printStackTrace();
            return null;
        }
    }

    /**
     * 通过帧类型和数据内容组装一个完整的NFC数据包
     *
     * @param type        帧类型
     * @param dataContent 数据内容
     * @return 从起始标志到检验码的byte[]数据包
     */
    public static byte[] buildNFCData(int type, byte[] dataContent) {
        try {
            ByteArrayOutputStream outputStream = new ByteArrayOutputStream();
            DataOutputStream dataOutputStream = new DataOutputStream(outputStream);
            // 帧头
            dataOutputStream.writeShort(0xFFFF);
            // 帧长
            dataOutputStream.writeShort(((dataContent == null) ? 0 : dataContent.length) + 6);
            // 帧类型
            dataOutputStream.writeByte(type);
            // 数据内容
            if (ByteUtil.notNull(dataContent)) {
                dataOutputStream.write(dataContent);
            }
            // 校验和
            byte[] checkBytes = Arrays.copyOfRange(outputStream.toByteArray(), 2,
                    outputStream.toByteArray().length);
            int checksum = ByteUtil.computeBodyNum(checkBytes);
            dataOutputStream.writeByte(checksum);
            return outputStream.toByteArray();
        } catch (IOException e) {
            e.printStackTrace();
            return null;
        }
    }

    /**
     * 构建NFC私有指令的数据包
     *
     * @param ssid    SSID
     * @param password  密码
     * @return byte[]数据包
     */
    public static byte[] buildWiFiData(String ssid, String password, String gizIp) {
        return buildWiFiData(ssid, null, password, gizIp, false);
    }

    /**
     * 构建NFC-WiFi私有指令的数据包
     *
     * @param ssid    SSID
     * @param bssid    BSSID
     * @param password  密码
     * @param hasChineseChar  是否包含中文
     * @return byte[]数据包
     */
    public static byte[] buildWiFiData(String ssid, byte[] bssid, String password, String gizIp, boolean hasChineseChar) {
        try {
            ByteArrayOutputStream outputStream = new ByteArrayOutputStream();
            DataOutputStream dataOutputStream = new DataOutputStream(outputStream);
            // 配网标志位 1字节 标志位，用于App和WiFi固件程序控制, 默认0, App写入数据时置 1,
            // WiFi 固件读取数据后, 将此值置 0
            dataOutputStream.writeByte(1);
            // ClientType 1字节 触碰端是App还是华为FA, 默认0, App传递1
            dataOutputStream.writeByte(1);
            // InitValue 2字节 模块初始化标志位，默认未初始化，值为 0x550xaa 代表已初始化，
            // 其他代表未初始化。APP默认置0x55aa
            dataOutputStream.writeByte(0x55);
            dataOutputStream.writeByte(0xaa);

            // SSID长度 2字节-第一个字节type=s,第二个字节长度, App传入
            dataOutputStream.write("s".getBytes(StandardCharsets.UTF_8));
            dataOutputStream.writeByte(ssid.length());
            // SSID值 用户通过App配网传入的用户家庭路由器的SSID
            // dataOutputStream.write(ssid.getBytes(StandardCharsets.UTF_8));
            dataOutputStream.writeBytes(ssid);

            // PWD长度 2字节-第一个字节type=p,第二个字节长度, App 传入
            dataOutputStream.write("p".getBytes(StandardCharsets.UTF_8));
            dataOutputStream.writeByte(password.length());
            // PWD值 用户通过App配网传入的用户家庭路由器的密码
            dataOutputStream.write(password.getBytes(StandardCharsets.UTF_8));

            // PaaS IP长度 2字节-第一个字节type=i,第二个字节长度, App 传入
            dataOutputStream.write("i".getBytes(StandardCharsets.UTF_8));
            dataOutputStream.writeByte(gizIp.length());
            // PaaS IP值 App 传入 IoT PaaS 域名解析后的 IP 地址（例如 255.255.255.255）
            dataOutputStream.write(gizIp.getBytes(StandardCharsets.UTF_8));

            // 中文模组是不区分2.4G和5G是直接用bssid去连的,英文的5G会先去用ssid连，如果不成功，再切回xbssid去连。
            // BSSID 长度 2字节-第一个字节type=b,第二个字节长度, App 传入
            // SSID有中文时传入BSSID，没有中文时长度传0
            dataOutputStream.write("b".getBytes(StandardCharsets.UTF_8));
            if (hasChineseChar) {
                dataOutputStream.writeByte(bssid.length);
                dataOutputStream.write(bssid);
            } else {
                dataOutputStream.writeByte(0);
            }

            // 当 SSID 中包含中文时，SSID 和 BSSID 同时赋值（对SSID中文字符GBK编码），XSSID的长度置为0；
            // 当SSID中未包含中文字符时，需赋值 SSID、XBSSID，BSSID 的长度置为 0
            // XBSSID 长度 2字节-第一个字节type=x,第二个字节长度, App 传入
            dataOutputStream.write("x".getBytes(StandardCharsets.UTF_8));
            if (!hasChineseChar) {
                dataOutputStream.writeByte(bssid.length);
                dataOutputStream.write(bssid);
            } else {
                dataOutputStream.writeByte(0);
            }

            return outputStream.toByteArray();
        } catch (IOException e) {
            e.printStackTrace();
            return null;
        }
    }

    /**
     * 将byte数组转化为SerialModule
     */
    public static ParamInfo getSerialModule(byte[] bytes) {
        if (!ByteUtil.notNull(bytes)) {
            return null;
        }
        int length = bytes.length;
        ParamInfo model = new ParamInfo();
        // 功能码
        byte[] dataFrameOrder = Arrays.copyOfRange(bytes, 1, 2);
        model.funName = (short) ByteUtil.byteArrayToInt(dataFrameOrder);
        // 长度
        byte[] copyLength = Arrays.copyOfRange(bytes, 2, 3);
        model.press = (short) ByteUtil.byteArrayToInt(copyLength);
        //数据内容
        // model.condition = Arrays.copyOfRange(bytes, 3, length - 1);
        //数据校验
        byte[] crc = Arrays.copyOfRange(bytes, length - 1, length);
        model.stir = (short) ByteUtil.byteArrayToInt(crc);
        return model;
    }

    /**
     * 构建平台信息
     *
     * @return NFC协议中平台信息，20个字节，不够补&
     */
    public static String getPlatform() {
        String model = getSystemModel();
        String brand = getBrand();
        if (brand == null) {
            brand = getManufacturer();
        }
        if (brand != null && brand.length() >= 10) {
            brand = brand.substring(0, 10);
        }
        String platform = "A-" + (brand != null ? brand : "NONE") + "-" + (model != null ? model
                : "NONE");
        if (platform.length() > 20) {
            platform = platform.substring(0, 20);
        } else {
            StringBuilder sb = new StringBuilder(platform);
            int fillLen = 20 - platform.length();
            for (int i = 0; i < fillLen; i++) {
                sb.append("&");
            }
            platform = sb.toString();
        }
        return platform;
    }

    /**
     * 获取手机型号
     *
     * @return 手机型号
     */
    public static String getSystemModel() {
        return Build.MODEL;
    }

    /**
     * 获取手机品牌
     *
     * @return 手机品牌
     */
    public static String getBrand() {
        return Build.BRAND;
    }

    /**
     * 获取手机厂商
     *
     * @return 手机厂商
     */
    public static String getManufacturer() {
        return Build.MANUFACTURER;
    }
}
